/**
 * Created by gilles on 14-02-15.
 */
"use strict";

/**
 * Définit un lasso :
 *  - sélection rectangulaire
 *  - déplaçable (MOVING)
 *  - dimensionnable (RESIZING)
 *
 */

function Lasso(canvas) {
    this.canvas = canvas;
    this.ctx = canvas.getContext('2d'); // Le contexte du canvas où s'applique le lasso
    this.MODE_OFF = -1;         // Inactif
    this.MODE_DISPLAYING = 0;   // Affiché
    this.MODE_RESIZING = 1;     // En dimensionnement
    this.MODE_MOVING = 2;       // En déplacement
    this.mode = this.MODE_OFF;  // Le mode actif
    this.rect = new Rect12(canvas.width / 4, canvas.height / 4, canvas.width * 3 / 4, canvas.height * 3 / 4);
    this.lineWidth = 1;         // Épaisseur du tracé
    this.imgData = null;        // Sauvegarde de la partie de l'image que recouvre la sélection
    this.lastPointerPos = null; // Le décalage entre le coin supérieur gauche et le pointeur de souris à suivre

    /**
     * Efface la sélection
     */
    this.effacer = function () {
        // Restituer l'image d'après les paramètres du rectangle de sélection
        if (this.imgData != null) {
            var upperLeft = this.rect.getUpperLeftPos();
            this.ctx.putImageData(this.imgData, upperLeft.x - this.lineWidth, upperLeft.y - this.lineWidth);
        }
    }

    /**
     * Trace la sélection
     */
    this.afficher = function () {
        // Sauvegarde de la zone de l'image avant le tracé
        var upperLeft = this.rect.getUpperLeftPos();
        var w = this.rect.getWidth();
        var h = this.rect.getHeight();
        this.imgData = this.ctx.getImageData(upperLeft.x - this.lineWidth, upperLeft.y - this.lineWidth, w + this.lineWidth * 2, h + this.lineWidth * 2);
        this.ctx.beginPath();
        this.ctx.rect(upperLeft.x, upperLeft.y, w, h);
        this.ctx.stroke();
    }

    /**
     * Indique si la position pos est à l'intérieur du rectangle du lasso
     */
    this.isFollowing = function () {
        return ((this.MODE_MOVING === this.mode) || (this.MODE_RESIZING === this.mode)) ;
    }

    /**
     * Déclenche le mode MODE_MOVING à partir d'une position de pointeur
     */
    this.startMoving = function (pointerPos) {
        console.log('Début MODE_MOVING');
        this.mode = this.MODE_MOVING;
        this.effacer();
        // On enregistre l'offset qui va servir à définir les déplacements à effectuer
        //var upperLeft = this.rect.getUpperLeftPos();
        this.lastPointerPos = pointerPos;
        //console.log(upperLeft);
        //console.log(this.moveOffset);
        this.afficher();
    }

    /**
     * Déclenche le mode MODE_RESIZING à partir d'une position de pointeur
     */
    this.startResizing = function (pointerPos) {
        console.log('Début MODE_RESIZING');
        this.mode = this.MODE_RESIZING;
        this.effacer();
        // Le rectangle est remis à zéro
        this.rect.pos1 = pointerPos;
        this.rect.pos2 = pointerPos;
        this.afficher();
    }

    /**
     * Suivant la position du pointeur par rapport à la sélection, déclenche le mode approprié:
     *  - RESIZING si le poineur est à l'EXTÉRIEUR de la sélection
     *  - MOVING si le poineur est à l'INTÉRIEUR de la sélection<
     */
    this.startFollowing = function (pointerPos) {
        if ( ! this.isFollowing()) {
            if (this.rect.pointIsIn(pointerPos)) {
                this.startMoving(pointerPos);
            } else {
                this.startResizing(pointerPos);
            }
        } else {
            // Déclencher Exception
        }
    }

    /**
     * Termine l'un des deux modes (MODE_MOVING ou MODE_RESIZING) de suivi du pointeur de souris
     */
    this.stopFollowing = function () {
        if (this.isFollowing()) {
            if (this.MODE_MOVING === this.mode) {
                this.lastPointerPos = null; // Supprime l'objet offset (type Point) créé pour le MODE_MOVING
            }
            this.mode = this.MODE_DISPLAYING;
        } else {
            // Déclencher Exception
        }
    }

    /**
     * Suit le point pos (en mode MOVING ou RESIZING)
     */
    this.doFollow = function (posXY) {
        this.effacer();
        switch (this.mode) {
            case this.MODE_MOVING:
                this.rect.moveXY(posXY.x - this.lastPointerPos.x, posXY.y - this.lastPointerPos.y);
                this.lastPointerPos = posXY;
                break;
            case this.MODE_RESIZING:
                this.rect.pos2 = posXY;
                break;
            default :
            // Déclencher Exception
        }
        this.afficher();
    }

    /**
     * Écouteur sur mousedown
     */
    this.listenTo_mousedown = function (event) {
        if (! this.isFollowing()) {
            var pointerPos = eventToCanvasXY(this.canvas, event);
            this.startFollowing(pointerPos);
        }
    };

    /**
     * Écouteur sur mouseup
     */
    this.listenTo_mouseup = function (event) {
        if (this.isFollowing()) {
            this.stopFollowing()
        }
    };

    /**
     * Écouteur sur mousemove
     */
    this.listenTo_mousemove = function (event) {
        if (this.isFollowing()) {
            var pointerPos = eventToCanvasXY(this.canvas, event);
            this.doFollow(pointerPos);
        }
    };



    // Bouton souris enfoncé sur le canvas
    canvas.addEventListener('mousedown', this.listenTo_mousedown.bind(this), false);

    // Bouton souris relaché sur le canvas
    canvas.addEventListener('mouseup', this.listenTo_mouseup.bind(this), false);

    // Souris déplacée sur le canvas
    canvas.addEventListener('mousemove', this.listenTo_mousemove.bind(this), false);

    return this;
}


